package com.cy.pj.common.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

/**
 * 日志切面,记录方法执行的时间
 * 
 * 使用注解`@Aspect`标识这个类为切面类型对象
 * 
 * 切面对象中包含两个部分:
 * 
 * 1. 切入点:切入扩展功能的点(要进行代理的方法,或者类)
 * 
 * 2. 通知:要执行的扩展类
 *
 */

@Component
@Aspect
@Slf4j
public class TimeLogAspect {

	/**
	 * 使用注解`@Piointcut`标识一个切入点
	 * 
	 * 其中的值为切入点的位置,这里使用的bean声明法
	 */
	// @Pointcut("execution(* com.cy.pj.sys.service.*.*(..))")
	@Pointcut("bean(userServiceImpl)")
	public void logPointcut() {
	}

	/**
	 * 记录方法执行的时间, 如果执行错误,要输出错误日志
	 *
	 * 使用注解`@Around`标识一个环绕通知
	 *
	 * 环绕通知可以在方法执行前和执行后进行运行
	 */
	@Around("logPointcut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

		long startTime = System.currentTimeMillis();

		try {

			/*
			 * jionPoint.proceed()
			 * 会调用本切面的其他通知,或者下一个切面的通知,或者目标方法
			 * 这里是有一定逻辑顺序的
			 */
			Object result = joinPoint.proceed();

			long endTime = System.currentTimeMillis();

			log.info("方法{}执行时间: {} ms", joinPoint.getSignature().getName(), endTime - startTime);

			return result;
		} catch (Throwable e) {
			log.error("方法执行异常: {}", e.getMessage(), e);
			throw e;
		}

	}

	@Before("logPointcut()")
	public void timeBefore() {
		log.info("doTimeBefore");
	}
}
